#[cfg(test)]
pub mod test_lifecycle {
    /*
生命周期 
.Rust的每个引用都有自己的生命周期。
．生命周期：引用保持有效的作用域。
．大多数情况：生命周期是隐式的、可被推断的
．当引用的生命周期可能以不同的方式互相关联时：手动标注生命周期。
```
    let r;
    {
        let x = 5;
        r = &x;
    }
    println!("r = {}", r);
```
 */

    use std::fmt::Display;

 /*
生命周期的主要目标：避免悬垂引用（dangling reference)
  */
    #[test]
    fn life01() {
        let s1 = String::from("str1");
        let s2 = "aa";
        let l = long(s1.as_str(), s2);
        println!("long = {}", l);
    }

    // fn lang(x: &str, y: &str) -> &str {}
    // 声明生命周期'a, 且指定x y 返回 都是这个生命周期
    fn long<'a>(x: &'a str, y: &'a str) -> &'a str {
        if x.len() > y.len() {
            x
        } else {
            y
        }
    }

    /*生命周期标注语法
．生命周期的标注不会改变引用的生命周期长度
．当指定了泛型生命周期参数，函数可以接收带有任何生命周期的引用
．生命周期的标注：描述了多个引用的生命周期间的关系，但不影响生命周期
 */

 /*生命周期标注﹣语法
．生命周期参数名：
    ﹣以'开头
    ﹣通常全小写且非常短
    ﹣很多人使用'a
．生命周期标注的位置：
    ﹣在引用的＆符号后
    ﹣使用空格将标注和引用类型分开
 */

 /*生命周期标注﹣例子
- &i32  //一个引用
- &'ai32 //带有显式生命周期的引用
- &'a mut i32 //带有显式生命周期的可变引用

- 单个生命周期标注本身没有意义
 */

 /*
函数签名中的生命周期标注
．泛型生命周期参数声明在：函数名和参数列表之间的＜＞里.
．生命周期'a的实际生命周期是：x和y两个生命周期中较小的那个
 */
    #[test]
    fn life02() {
        let s1 = String::from("str1");
        let r1;
        {
            let s2 = String::from("s2");
            r1 = long(s1.as_str(), s2.as_str());
            println!("result in = {}", r1);
        }
        // 到这里s2 已经结束了
        // println!("result = {}", r1);
    }

/*
深入理解生命周期
．指定生命周期参数的方式依赖于函数所做的事情
.从函数返回引用时，返回类型的生命周期参数需要与其中一个参数的生命周期匹配：
．如果返回的引用没有指向任何参数，那么它只能引用函数内创建的值：
    ﹣这就是悬垂引用：该值在函数结束时就走出了作用域
 */

    #[test]
    fn lefe03() {
        let s1 = String::from("s1value");
        let s2 = String::from("s2value");
        long03(s1.as_str(), s2.as_str());
    }

    // fn long03<'a>(x: &'a str, y: &str) -> &'a str {
    //     let re = String::from("long03 str");
    //     re.as_str()
    // }

    fn long03<'a>(x: &'a str, y: &str) -> String {
        let re = String::from("long03 str");
        re
    }

    /*
    Struct 定义中的生命周期标注
    .Struct里可包括：
        ﹣引用：需要在每个引用上添加生命周期标注
        ﹣自持有的类型
    */
    struct LifeTest<'a> {
        p1: &'a str,
    }

    #[test]
    fn lefe04() {
        let s1 = String::from("111aaa.222333");
        let s2 = s1.split(".").next().expect("split next error");
        let lt = LifeTest{
            p1: s2
        };
    }

    /* 生命周期省略规则
    ．在 Rust 引用分析中所编入的模式称为生命周期省略规则。
        ﹣这些规则无需开发者来遵守
        ﹣它们是一些特殊情况，由编译器来考虑
        ﹣如果你的代码符合这些情况，那么就无需显式标注生命周期
    ．生命周期省略规则不会提供完整的推断：
        ﹣如果应用规则后，引用的生命周期仍然模糊不清→编译错误
        ﹣解决办法：添加生命周期标注，表明引用间的相互关系

    输入、输出生命周期 
    ．生命周期在：
        ﹣函数／方法的参数：输入生命周期
        ﹣函数／方法的返回值：输出生命周期

    生命周期省略的三个规则
    ．编译器使用3个规则在没有显式标注生命周期的情况下，来确定引用的生命周期
        - 规则 1 应用于输入生命周期
        ﹣规则2、3应用于输出生命周期
        ﹣如果编译器应用完3个规则之后，仍然有无法确定生命周期的引用→报错
        ﹣这些规则适用于 fn定义和impl块
    ．规则1：每个引用类型的参数都有自己的生命周期
    ．规则2：如果只有1个输入生命周期参数，那么该生命周期被赋给所有的输出生命周期参数
    ．规则3：如果有多个输入生命周期参数，但其中一个是＆self或＆mut self（是方法），那么self的生命周期会被赋给所有的输出生命周期参数

    生命周期省略的三个规则﹣例子
    ．假设我们是编译器：
    ·fn first_word(s:&str)->&str {
    ·fn first_word<'a>(s:&'astr)>&str{
    ·fn first_word<'a>(s: &'a str) -> &'a str {
    ·fn longest(x: &str, y: &str) -> &str {
    ·fn longest<'a, 'b>(x: &'a str, y: &'b str) -> &str {

    方法定义中的生命收起标注
    .在struct上使用生命周期实现方法，语法和泛型参数的语法一样
    .在哪声明和使用生命周期参数，依赖于：
        ﹣生命周期参数是否和字段、方法的参数或返回值有关
    .struct字段的生命周期名：
        - 在impl后声明
        ﹣在struct名后使用
        ﹣这些生命周期是struct类型的一部分
    .impl块内的方法签名中：
        ﹣引用必须绑定于struct字段引用的生命周期，或者引用是独立的也可以
        ﹣生命周期省略规则经常使得方法中的生命周期标注不是必须的
    */

    impl<'a> LifeTest<'a> {
        fn func1(&self) -> i32 {
            61
        }
        fn func2(&self, s: &str) -> &str {
            println!("func2 s = {}", s);
            self.p1
        }
    } 
    #[test]
    fn life05() {
        
    }

    /* 静态生命周期
    .'static 是一个特殊的生命周期：整个程序的持续时间。
        - 例如：所有的字符串字面值都拥有'static生命周期
        ` let s: &'static str = "I have a static lifetime."; `
    ．为引用指定'static生命周期前要三思：
        ﹣是否需要引用在程序整个生命周期内都存活。
     */

    /* 泛型参数类型、Trait Bound、生命周期 */
    fn long06<'a, T>(x: &'a str, y: &'a str, t: T) -> &'a str
    where 
        T: Display
    {
        println!("long06 t = {}", t);
        if x.len() > y.len() {
            x
        } else {
            y
        }
    }
    #[test]
    fn life06() {
        
    }

}